﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Tp.Dto.Allgemein
{
	  public class InPcBase : INotifyPropertyChanged
	  {
			/// <summary>
			/// Wird geworfen, wenn eine Eigenschaft des Objektes einen neuen Wert bekommt.
			/// </summary>
			public event PropertyChangedEventHandler PropertyChanged;

			/// <summary> Wirft das PropertyChanged-Ereignis dieses Objektes.</summary>
			/// <param name="eigenschaftsName">Der Name der Eigenschaft, die den neuen Wert hat.</param>
			protected virtual void RaisePropertyChanged(string eigenschaftsName)
			{
				  PropertyChangedEventHandler handler = this.PropertyChanged;
				  if (handler != null)
				  {
						handler(this, new PropertyChangedEventArgs(eigenschaftsName));
				  }
			}

			/// <summary> Wirft das PropertyChanged-Ereignis dieses 
			///   Objektes für jede Eigenschaft aus propertyNames.</summary>
			/// <param name="eigenschaftsNamen">Der Namensliste der Eigenschaften, die einen neuen Wert haben.</param>
			protected void RaisePropertyChanged(params string[] eigenschaftsNamen)
			{
				  foreach (var name in eigenschaftsNamen)
				  {
						this.RaisePropertyChanged(name);
				  }
			}

			/// <summary> Wirft das PropertyChanged-Ereignis dieses Objektes.</summary>
			/// <typeparam name="T">Der Typ der Eigenschaft, die den neuen Wert hat.</typeparam>
			/// <param name="eigenschaftsLamdaAusdruck">Ein Lambda-Ausdruck, der 
			///   Eigenschaft, die einen neuen Wert hat.</param>
			protected void RaisePropertyChanged<T>(Expression<Func<T>> eigenschaftsLamdaAusdruck)
			{
				  var propertyName = ExtractPropertyName(eigenschaftsLamdaAusdruck);
				  this.RaisePropertyChanged(propertyName);
			}

			private string ExtractPropertyName<T>(Expression<Func<T>> eigenschaftsAusdruck)
			{
				  if (eigenschaftsAusdruck == null)
				  {
						throw new ArgumentNullException("eigenschaftsAusdruck");
				  }

				  var memberExpression = eigenschaftsAusdruck.Body as MemberExpression;
				  if (memberExpression == null)
				  {
						throw new ArgumentException("Der Ausdruck ist kein Member-Lamda-Ausdruck (MemberExpression).", "eigenschaftsAusdruck");
				  }

				  var property = memberExpression.Member as PropertyInfo;
				  if (property == null)
				  {
						throw new ArgumentException("Der Member-Ausdruck greift nicht auf eine Eigenschaft zu.", "eigenschaftsAusdruck");
				  }

				  if (!property.DeclaringType.IsAssignableFrom(this.GetType()))
				  {
						throw new ArgumentException("Die referenzierte Eigenschaft gehört nicht zum gewünschten Typ.", "eigenschaftsAusdruck");
				  }

				  var getMethod = property.GetGetMethod(true);
				  if (getMethod == null)
				  {
						// das sollte nicht auftreten ...
						throw new ArgumentException("Die referenzierte Eigenschaft hat keine 'get' - Methode.", "eigenschaftsAusdruck");
				  }

				  if (getMethod.IsStatic)
				  {
						throw new ArgumentException("Die refrenzierte Eigenschaft ist statisch.", "eigenschaftsAusdruck");
				  }

				  return memberExpression.Member.Name;
			}
	  }
}
